<!DOCTYPE html>
<html lang='en'>
<head>
    <meta charset='UTF-8'>
    <title>Chat Demo</title>
    <link href='css/common.css' rel='stylesheet' type='text/css'>
    <link href='css/chat.css' rel='stylesheet' type='text/css'>
    <script src='js/vue.js' type='text/javascript'></script>
    <script src='js/vue-resource-v1.5.1.js' type='text/javascript'></script>
</head>
<body style='background-image: url("img/bg_chat.jpg") ;background-size:100% 100%;background-repeat: no-repeat;background-attachment:fixed;'>
    <div id='app'>
        <h1 id='logo' v-if='!loginSuccess'>Chat</h1>
        <!-- 登录与注册 -->
        <div id='login' v-if='!loginSuccess'>
            <!-- 登录与注册 -->
            <div class='title'>
                <a v-bind:class="loginBtnIsActive?'active':''" v-on:click='onLoginTabClick'>{{loginBtnText}}</a>
                <b>·</b>
                <a v-bind:class="loginBtnIsActive?'':'active'" v-on:click='onRegisterTabClick'>{{registerBtnText}}</a>
            </div>
            <!-- 登录 -->
            <div v-if='loginBtnIsActive'>
                <div class='input-box'>
                    <input id='loginName' type='text' style='background: transparent url("./img/ic_user.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='用户名/电话/邮箱'/>
                    <div class='divider'></div>
                    <input id='loginPassword' type='password' style='background: transparent url("./img/ic_password.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='密码长度为6位'/>
                </div>
                <div style='align-items: center;margin-top: 20px'>
                    <input type='checkbox' style='width: 30px;height: 30px;float: left;'/>
                    <span style='float: left;margin-left: 5px;text-align: center;line-height: 30px;color:#2E3238;'>记住我</span>
                    <a href='' style='float: right;line-height: 30px;color: #2E3238;'>忘记密码</a>
                </div>
                <div>
                    <a class='login-btn' type='button' v-on:click='onLoginBtnClick'>{{loginBtnText}}</a>
                </div>
            </div>
            <!-- 注册 -->
            <div v-if='!loginBtnIsActive'>
                <div class='input-box'>
                    <input v-model='registerInfo.inputUserName' type='text'
                           style='background: transparent url("./img/ic_user.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='用户名'/>
                    <div class='divider'></div>
                    <input v-model='registerInfo.inputPhone' type='phone'
                           style='background: transparent url("./img/ic_phone.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='手机号'/>
                    <div class='divider'></div>
                    <input v-model='registerInfo.inputEmail' type='email'
                           style='background: transparent url("./img/ic_mail.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='邮箱'/>
                    <div class='divider'></div>
                    <input v-model='registerInfo.inputPassword' type='password'
                           style='background: transparent url("./img/ic_password.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='设置密码，密码长度为6位'/>
                    <div class='divider'></div>
                    <input v-model='registerInfo.inputPasswordAgain' type='password'
                           style='background: transparent url("./img/ic_password.png") no-repeat left;
                    background-size: 20px 20px;background-position-x: 15px;'
                           placeholder='再次输入密码'/>
                </div>
                <div>
                    <a class='register-btn' type='button' v-on:click='onRegisterBtnClick'>{{registerBtnText}}</a>
                </div>
            </div>
        </div>
        <!-- 对话区 -->
        <transition name='mainTransition'>
            <div class='main' v-if='loginSuccess'>
                <!-- 左侧列表区 -->
                <div class='left'>
                    <!--用户信息-->
                    <div class='user_info'>
                        <img class='user_head' src='img/ic_head_default.jpg'/>
                        <div class='user_name'>{{loginUserName}}
                            <div>
                                <a class='user_status'>{{socketStatus}}</a>
                            </div>
                        </div>
                    </div>
                    <div style='background-color: #2E3238;height: 2px'></div>
                    <!-- 用户列表 -->
                    <ul class='user_list'>
                        <li class='user_item' v-for='(item,index) in userList' @click='changeChatUser(item)'>
                            <img class='user_head' src='img/ic_head_default.jpg'/>
                            <div style='width:150px;padding-left: 10px;'>
                                <div style='float: left;width:100%;height: 20px;font-size: 16px;color: #ffffff;font-weight:bold'>
                                    {{item.name}}
                                </div>
                                <div style='float: left;width:100%;height: 20px;margin-top: 5px;font-size: 10px;color: #abcabc;'>
                                    [{{item.isOnline ? '在线' : '离线'}}]
                                </div>
                            </div>
                            <span style='width: 40px;height: 40px;padding-left: 10px;font-size: 10px;'>12-11</span>
                        <li>
                    </ul>
                </div>
                <!-- 右侧对话区 -->
                <div class='right'>
                    <!--联系人-->
                    <div class='chat_user_name'>{{chatUserName}}</div>
                    <!-- 分割线 -->
                    <hr color='#D6D6D6' size='1' align='center' style='margin:0px 10px;'/>
                    <!--消息列表-->
                    <ul class='msg_list'>
                        <li v-for='item in msgList1'>
                            <div v-bind:class='item["isSend"] ? "msg_item msg_item_me":"msg_item msg_item_other" '>
                                <img v-bind:class='item["isSend"] ?"msg_item_head msg_item_me":"msg_item_head msg_item_other" '
                                     src='img/ic_head_default.jpg'/>
                                <p v-bind:class='item["isSend"] ?"msg_item_text msg_item_me":"msg_item_text msg_item_other" '>
                                    {{item['msg']}}</p>
                            </div>
                        <li>
                    </ul>
                    <!--输入框-->
                    <div class='chat_input'>
                        <textarea id='text' class='edit_text' type='text' placeholder='输入聊天内容'></textarea>
                        <button class='btn_send' @click='sendChatMsg'>发送</button>
                    </div>
                </div>
            </div>
        </transition>
    </div>
    <script>
      // var host = "ws://192.168.230.133:9997";
      let host = 'ws://localhost:20002'
      let websocket = null
      let loginUserId = ''
      let loginUserName = ''
      let currentContactUser = null
      // 监听窗口关闭事件，当窗口关闭时，主动去关闭websocket连接，防止连接还没断开就关闭窗口，server端会抛异常。
      window.onbeforeunload = function () {
        websocket.close()
      }
      let app = new Vue({
        el: '#app',
        data: {
          loginBtnText: '登录',
          registerBtnText: '注册',
          loginBtnIsActive: true,
          loginSuccess: false,
          loginUserName: '',
          socketStatus: '未连接',
          userList: [],
          chatUserName: '',
          chatUserId: '',
          msgList: {},
          msgList1: [],
          registerInfo: {
            inputUserName: '',
            inputEmail: '',
            inputPhone: '',
            inputPassword: '',
            inputPasswordAgain: '',
          },
        },
        methods: {
          onLoginTabClick: function (event) {
            this.loginBtnIsActive = true
          },
          onRegisterTabClick: function (event) {
            this.loginBtnIsActive = false
          },
          onRegisterBtnClick: function (event) {
            console.log(JSON.stringify(this.registerInfo))
            if (this.registerInfo.inputUserName.trim().length === 0) {
              alert('用户名不能为空')
              return
            }
            if (this.registerInfo.inputPhone.trim().length === 0) {
              alert('电话不能为空')
              return
            }
            if (this.registerInfo.inputPassword.trim().length === 0) {
              alert('密码不能为空')
              return
            }
            if (this.registerInfo.inputPassword.trim().length === 0) {
              alert('密码不能为空')
              return
            }
            if (this.registerInfo.inputPassword.trim().length < 6) {
              alert('密码至少为6位')
              return
            }
            if (this.registerInfo.inputPassword.trim() !== this.registerInfo.inputPasswordAgain.trim()) {
              alert('两次输入密码不一致')
              return
            }

            this.$http.post(
              'http://localhost:9001/auth/register',
              {
                name: this.registerInfo.inputUserName,
                password: this.registerInfo.inputPassword,
                phone: this.registerInfo.inputPhone,
                email: this.registerInfo.inputEmail,
              }, {
                'headers': {
                  'Content-Type': 'application/json',
                  'Access-Control-Allow-Origin': '*',
                },
              }).then(function (response) {
                let data = response.data
                console.log('接口返回数据：' + JSON.stringify(data))
                if (data.code === 200) {
                  alert('注册成功')
                  this.loginBtnIsActive = true
                } else {
                  alert('出错了：' + data.msg)
                }
              },
              function () {
                alert('注册失败，请稍候重试！')
              })
          },
          onLoginBtnClick: function (event) {
            let name = document.getElementById('loginName').value
            if (name.trim().length === 0) {
              alert('用户名不能为空')
              return
            }
            let password = document.getElementById('loginPassword').value
            if (password.trim().length === 0) {
              alert('密码不能为空')
              return
            }
            // 登录认证
            this.$http.post(
              'http://localhost:9001/auth/login',
              {
                userName: name,
                password: password,
              }, {
                'headers': {
                  'Content-Type': 'application/json',
                  'Access-Control-Allow-Origin': '*',
                },
              }).then(function (response) {
                let data = response.data
                console.log('接口返回数据：' + JSON.stringify(data))
                if (data.code === 200) {
                  loginUserId = data.data.id
                  loginUserName = data.data.name
                  app.$data.loginSuccess = true
                  app.$data.loginUserName = loginUserName
                  app.getFriendList()
                } else {
                  alert('登录出错：' + data.msg)
                }
              },
              function () {
                alert('调用接口失败！')
              })
          },
          // 获取好友列表
          getFriendList: function () {
            // 登录认证
            this.$http.get(
              'http://localhost:9001/friend/list',
              {
                params: {
                  userId: loginUserId,
                },
              },
            ).then(function (response) {
                let data = response.data
                console.log('接口返回数据：' + JSON.stringify(data))
                if (data.code === 200) {
                  let userList = data.data
                  userList.forEach((item) => {
                    item.isOnline = false
                  })
                  app.$data.userList = userList
                  if (data.data.length > 0) {
                    currentContactUser = data.data[0]
                    app.$data.chatUserId = currentContactUser.id
                    app.$data.chatUserName = currentContactUser.name
                  }
                } else {
                  console.log('登录出错：' + data.msg)
                }
                app.connectChatServer()
              },
              function () {
                console.info('调用接口失败！')
                app.connectChatServer()
              })
          },
          // 连接聊天服务器
          connectChatServer: function () {
            // 判断当前浏览器是否支持WebSocket
            if ('WebSocket' in window) {
              websocket = new WebSocket(host)
            } else if ('MozWebSocket' in window) {
              websocket = new MozWebSocket(host)
            } else {
              app.$data.socketStatus = '该浏览器不支持WebSocket！'
            }
            // 连接成功建立的回调方法
            websocket.onopen = function (event) {
              console.log('websocket连接成功')
              app.$data.socketStatus = '已连接'
              // 发送socket认证消息
              let loginMsg = {}
              loginMsg.messageType = 'LOGIN'
              loginMsg.clientType = 'web'
              loginMsg.fromUserId = loginUserId
              loginMsg.toUserId = 0
              loginMsg.userId = loginUserId
              loginMsg.userName = loginUserName
              loginMsg.location = '暂无'
              loginMsg.login = true
              let str = JSON.stringify(loginMsg)
              console.log('websocket发送登录信息：' + str)
              websocket.send(str)
            }
            // 接收到消息的回调方法
            websocket.onmessage = function (event) {
              let data = event.data
              console.log('websocket收到消息：' + data)
              // 针对消息类型进行解析
              let json = JSON.parse(data)
              let type = json['messageType']
              /**
               * HEARTBEAT(0, "心跳"),
               * LOGIN(1, "登录"),
               * NOTIFY(2, "通知"),
               * APPLY(3, "申请"),
               * CHAT(4, "聊天"),
               * FORWARD(5, "转发");
               */
              switch (type) {
                case 'HEARTBEAT': // 心跳
                  console.log('websocket收到心跳信息')
                  break
                case 'LOGIN': // 登录
                  break
                case 'NOTIFY': // 通知
                  let notifyMessageType = json['notifyMessageType']
                  if (notifyMessageType === 'LOGIN_REPLY') {// 登录回复
                    let onlineIds = JSON.parse(json['data'])
                    console.log('当前在线好友列表为：' + JSON.stringify(onlineIds))
                    if (onlineIds.length > 0 && app.$data.userList.length > 0) {
                      app.$data.userList.forEach((item) => {
                        if (onlineIds.includes(item.id)) {
                          item.isOnline = true
                        } else {
                          item.isOnline = false
                        }
                      })
                    }
                  } else if (notifyMessageType === 'LOGIN_NOTIFY') {// 登录通知
                    let loginBody = JSON.parse(json['data'])
                    for (let item of app.$data.userList) {
                      if (item['id'] === loginBody['id']) {
                        item.isOnline = loginBody['login']
                        break
                      }
                    }
                  } else if (notifyMessageType === 'CHAT_MESSAGE_ID') {// 消息ID通知，等价于通知消息发送成功

                  } else {// 重要通知

                  }
                  break
                case 'APPLY': // 申请

                  break
                case 'CHAT':// 聊天
                  let fromUserId = json['fromUserId']
                  console.log('消息来源：', fromUserId)
                  app.handleMsg(fromUserId, json)
                  break
                default:
                  break
              }
            }
            // 连接发生错误的回调方法
            websocket.onerror = function () {
              app.$data.socketStatus = '连接出错'
            }
            // 连接关闭的回调方法
            websocket.onclose = function () {
              app.$data.socketStatus = '连接关闭'
            }
          },
          // 切换聊天对象
          changeChatUser: function (item) {
            console.log('点击的用户信息:' + JSON.stringify(item))
            if (currentContactUser !== null && item['id'] === currentContactUser['id']) {
              console.log('对话为同一用户')
            } else {
              console.log('变更了对话用户')
              currentContactUser = item
              this.chatUserId = item['id']
              this.chatUserName = item['name']
              this.msgList1 = this.msgList[this.chatUserId]
            }
          },
          // 发送消息
          sendChatMsg: function () {
            let chatMessage = {}
            chatMessage.messageType = 'CHAT'
            chatMessage.chatMessageType = 'SINGLE'
            chatMessage.fromUserId = loginUserId
            chatMessage.toUserId = this.chatUserId
            chatMessage.bodyType = 'TEXT'
            let textBody = {'text': document.getElementById('text').value}
            chatMessage.body = textBody
            let msg = JSON.stringify(chatMessage)
            console.log('websocket发送消息：', msg)
            websocket.send(msg)
            this.handleMsg(this.chatUserId, chatMessage, true)
            document.getElementById('text').value = ''
          },
          // 处理消息
          handleMsg: function (contactUserId, chatMessage, isSend) {
            console.log('联系人', contactUserId)
            let bodyType = chatMessage.bodyType
            let msg = ''
            if (bodyType === 'TEXT') {
              if (typeof chatMessage.body === 'string') {
                msg = JSON.parse(chatMessage.body).text
              } else {
                msg = chatMessage.body.text
              }
            } else {
              msg = JSON.stringify(chatMessage.body)
            }
            let msgArray = this.msgList[contactUserId]
            if (msgArray == null || msgArray.length === 0) {
              msgArray = []
              this.msgList[contactUserId] = msgArray
            }
            let saveMsg = {
              isSend,
              msg,
            }
            msgArray.push(saveMsg)
            if (contactUserId === this.chatUserId) {
              this.msgList1 = this.msgList[contactUserId]
            }
            console.log('消息列表：' + JSON.stringify(app.$data.msgList))
          },
          // 关闭连接
          closeWebSocket: function () {
            websocket.close()
          },
        },
      })
    </script>
</body>
</html>
<!-- 总结：
1.控制组件的显示与隐藏：
 1.1 使用v-if='标志位'
 1.2 使用v-bind:class="标志位？'显示css样式':'隐藏css样式'" -->
